namespace MLP.NeuralNet
{
	using System;

	// Sigmoid activation function
	//
	//                1
	// f(x) = ------------------
	//        1 + exp(-alfa * x)
	//
	// Output range: [0, 1]
	//
	[Serializable]
	public class SigmoidFunction : IVisual.I_ActivationFunction
	{
		private float alfa = 2;

		public float Alfa
		{
			get { return alfa; }
			set { alfa = value; }
		}

		public SigmoidFunction()
		{ }
		public SigmoidFunction(float alfa)
		{
			this.alfa = alfa;
		}
		
		// Funktionswert berechnen
		public float Output(float x)
		{
			cls_Rechen_LOG.WRITE_LOG_LINE("\t\t\tOutput -> (1 / (1 + Math.Exp(-alfa * x))) => (1 / (1 + Math.Exp(" + (-alfa) + " * " + x + "))) = " + (1 / (1 + Math.Exp(-alfa * x))));
			return (float) (1 / (1 + Math.Exp(-alfa * x)));
		}

		// differenzieller Funktionswert
		public float OutputPrime(float x)
		{
			float y = Output(x);

			cls_Rechen_LOG.WRITE_LOG_LINE("\t\tOutputPrime -> (alfa * y * (1 - y)) => (" + alfa + " * " + y + " * (" + (1 - y) + ")) = " + (alfa * y * (1 - y)));
			return (float) (alfa * y * (1 - y));
		}

		// differenzieller Funktionswert
		// Funktionswert als eingabe
		public float OutputPrime2(float y)
		{
			cls_Rechen_LOG.WRITE_LOG_LINE("\t\tOutputPrime2 -> (alfa * y * (1 - y)) => (" + alfa + " * " + y + " * (" + (1 - y) + ")) = " + (alfa * y * (1 - y)));
			return (float) (alfa * y * (1 - y));
		}

		public string NAME()
		{
			return "SigmoidFunction";
		}
	}


	// Bipolar Sigmoid activation function
	//
	//                1
	// f(x) = ------------------ - 0.5
	//        1 + exp(-alfa * x)
	//
	// Output range: [-0.5, 0.5]
	//
	[Serializable]
	public class BipolarSigmoidFunction : IVisual.I_ActivationFunction
	{
		private float alfa = 2;

		public float Alfa
		{
			get { return alfa; }
			set { alfa = value; }
		}

		public BipolarSigmoidFunction()
		{ }
		public BipolarSigmoidFunction(float alfa)
		{
			this.alfa = alfa;
		}
		
		public float Output(float x)
		{
			cls_Rechen_LOG.WRITE_LOG_LINE("\t\t\tOutput -> ((1 / (1 + Math.Exp(-alfa * x))) - 0.5) => (1 / (1 + Math.Exp(" + (-alfa) + " * " + x + ")) - 0.5) = " + ((1 / (1 + Math.Exp(-alfa * x))) - 0.5));
			return (float) ((1 / (1 + Math.Exp(-alfa * x))) - 0.5);
		}

		public float OutputPrime(float x)
		{
			float y = Output(x);

			cls_Rechen_LOG.WRITE_LOG_LINE("\t\t\tOutputPrime -> (alfa * (0.25 - y * y)) => (" + (-alfa) + " * 0.25 - " + y + " * " + y + ")) = " + (alfa * (0.25 - y * y)));
			return (float) (alfa * (0.25 - y * y));
		}

		public float OutputPrime2(float y)
		{
			cls_Rechen_LOG.WRITE_LOG_LINE("\t\t\tOutputPrim2 -> (alfa * (0.25 - y * y)) => (" + alfa + " * (0.25 - " + y + " * " + y + ")) = " + (alfa * (0.25 - y * y)));

			return (float) (alfa * (0.25 - y * y));
		}

		public string NAME()
		{
			return "BipolarSigmoidFunction";
		}
	}


	// Hyperbolic Tangens activation function
	//
	//                         exp(alfa * x) - exp(-alfa * x)
	// f(x) = tanh(alfa * x) = ------------------------------
	//                         exp(alfa * x) + exp(-alfa * x)
	//
	// Output range: [-1, 1]
	//
	[Serializable]
	public class HyperbolicTangensFunction : IVisual.I_ActivationFunction
	{
		private float alfa = 1;

		public float Alfa
		{
			get { return alfa; }
			set { alfa = value; }
		}

		public HyperbolicTangensFunction()
		{ }
		public HyperbolicTangensFunction(float alfa)
		{
			// alpha/2 = sigmoide aktivierungsfunktion
			this.alfa = alfa;
		}

		public float Output(float x)
		{
			cls_Rechen_LOG.WRITE_LOG_LINE("\t\t\tOutput -> (Math.Tanh(alfa * x)) => (Math.Tanh(" + alfa + " * " + x + ")) = " + (Math.Tanh(alfa * x)));

			return (float) (Math.Tanh(alfa * x));
		}

		public float OutputPrime(float x)
		{
			float y = Output(x);
			cls_Rechen_LOG.WRITE_LOG_LINE("\t\t\tOutputPrime -> (alfa * (1 - y * y)) => (" + alfa + " * (1 - " + y + " * " + y + ")) = " + (alfa * (1 - y * y)));

			return (float) (alfa * (1 - y * y));
		}

		public float OutputPrime2(float y)
		{
			cls_Rechen_LOG.WRITE_LOG_LINE("\t\t\tOutputPrime2 -> (alfa * (1 - y * y)) => (" + alfa + " * (1 - " + y + " * " + y + ")) = " + (alfa * (1 - y * y)));

			return (float) (alfa * (1 - y * y));
		}

		public string NAME()
		{
			return "HyperbolicTangensFunction";
		}
	}
}
